/*
 * Licensed to the Tai Ping Jin Ke
 *
 * Copyright (c) 2022 .
 * All rights reserved.
 * 项目名称：呼叫中心-系统通用工具封装层
 * 版权说明：本软件属太平金融科技服务(上海)有限公司所有，在未获得太平金融科技服务(上海)有限公司正式授权情况下，任何企业和个人，不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。
 */
package com.taiping.cc.application.tools;

import cn.hutool.core.io.IoUtil;
import cn.hutool.http.HttpUtil;
import com.taipingframework.utility.constant.SystemConstant;
import com.taipingframework.utility.exception.UtilityException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;

import javax.servlet.http.HttpServletResponse;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.text.MessageFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;

/**
 * 改造为HttpClient实现下载文件的功能
 */
@Slf4j
public final class DownloadUtils {
//CHECKSTYLE:OFF

    /**
     * 本地服务器端下载并保存第三方远程服务器文件
     *
     * @param fileHttpUrl 目标文件的网络地址
     * @param saveAsPath  服务器存放路径
     */
    public static String downloadByNetwork(String fileHttpUrl, String saveAsPath) {
        File directoryPath = new File(saveAsPath);
        if (!directoryPath.exists()) {
            boolean hasSuccess = directoryPath.mkdir();
            if (!hasSuccess) {
                hasSuccess = directoryPath.mkdirs();
            }
            log.debug("路径{}的创建结果:{}", saveAsPath, hasSuccess);
        }
        String fileName = fileHttpUrl.substring(fileHttpUrl.lastIndexOf("/") + 1);
        fileName = MessageFormat.format("{0}/{1}", saveAsPath, formatOriginFileName(fileName));

        HttpURLConnection urlConnection = null;
        InputStream inStream = null;
        OutputStream outStream = null;
        try {
            urlConnection = getHttpInputStream(fileHttpUrl);
            inStream = urlConnection.getInputStream();

            File saveAsFile = new File(fileName);
            if (!saveAsFile.exists()) {
                boolean hasSuccess = saveAsFile.createNewFile();
                log.debug("文件{}的创建结果:{}", fileName, hasSuccess);
            }
            outStream = new FileOutputStream(saveAsFile);

            streamWriter(inStream, outStream, 4);
        } catch (Exception e) {
            log.error("file {} download failure:", fileHttpUrl, e);
            return null;
        } finally {
            closeStreamObject(outStream, inStream, urlConnection);
        }
        return fileName;
    }

    /**
     * 浏览器端下载本地服务器文件
     *
     * @param fileFullPath 服务器文件路径完全限定名
     * @param response     浏览器响应对象
     */
    public static void downloadByBrowser(String fileFullPath, HttpServletResponse response) {
        File file = new File(fileFullPath);
        String saveAsName = formatOriginFileName(file.getName());

        InputStream inStream = null;
        OutputStream outStream = null;
        try {
            inStream = new FileInputStream(file);
            outStream = getBrowserOutputStream(saveAsName, response);
            streamWriter(inStream, outStream, 1);
        } catch (IOException e) {
            log.error("file {} download failure:", file.getPath(), e);
        } finally {
            closeStreamObject(outStream, inStream, null);
        }
    }

    /**
     * 浏览器端通过本地服务器下载第三方远程服务器文件
     */
    public static void downloadFromRemote(String fileHttpUrl, HttpServletResponse response) {
        String fileName = fileHttpUrl.substring(fileHttpUrl.lastIndexOf("/") + 1);
        String saveAsName = formatOriginFileName(fileName);

        HttpURLConnection urlConnection = null;
        InputStream inStream = null;
        OutputStream outStream = null;
        try {
            urlConnection = getHttpInputStream(fileHttpUrl);
            inStream = urlConnection.getInputStream();
            outStream = getBrowserOutputStream(saveAsName, response);
            streamWriter(inStream, outStream, 4);
        } catch (Exception e) {
            log.error("file {} download failure:", fileHttpUrl, e);
        } finally {
            closeStreamObject(outStream, inStream, urlConnection);
        }
    }

    /**
     * 将网络文件包装为HTTP输出流
     */
    public static ResponseEntity<Resource> readResourceData(String objectUrl, String objectAlias) throws UtilityException {
        try (ByteArrayInputStream inputStream = IoUtil.toStream(HttpUtil.downloadBytes(objectUrl));
             ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {

            byte[] buffer = new byte[SystemConstant.BASE_UNIT];
            int length;
            while ((length = inputStream.read(buffer)) != SystemConstant.DEFAULT_INVALID) {
                outputStream.write(buffer, 0, length);
            }
            byte[] byteArray = outputStream.toByteArray();

            // 读取文件内容
            ByteArrayResource resource = new ByteArrayResource(byteArray);

            // 设置响应头
            HttpHeaders headers = new HttpHeaders();
            headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + java.net.URLEncoder.encode(objectAlias, StandardCharsets.UTF_8.name()));

            // 返回响应实体
            return ResponseEntity.ok()
                    .headers(headers)
                    .contentType(MediaType.APPLICATION_OCTET_STREAM)
                    .body(resource);
        } catch (Exception e) {
            throw new UtilityException(e);
        }
    }

    /**
     * 重新格式化文件名
     */
    private static String formatOriginFileName(String fileName) {
        String prefix = fileName.substring(0, fileName.lastIndexOf("."));
        String suffix = fileName.substring(fileName.lastIndexOf("."));
        fileName = prefix + "-" + System.currentTimeMillis() + suffix;
        return fileName;
    }

    /**
     * 根据Http协议的url获取连接对象
     */
    private static HttpURLConnection getHttpInputStream(String httpUrl) throws IOException {
        URL url = new URL(httpUrl);
        HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
        urlConnection.setDoInput(true);
        urlConnection.setConnectTimeout(1000 * 60);
        urlConnection.setRequestMethod("GET");
        urlConnection.setRequestProperty("Charset", "UTF-8");
        urlConnection.connect();
        return urlConnection;
    }

    /**
     * 通过浏览器下载文件时设置并获取输出流
     */
    private static OutputStream getBrowserOutputStream(String newFileNameSaveAs, HttpServletResponse response) throws IOException {
        newFileNameSaveAs = java.net.URLEncoder.encode(newFileNameSaveAs, "UTF-8");
        response.setHeader("Content-Disposition", MessageFormat.format("attachment; filename=\"{0}\"", newFileNameSaveAs));
        response.setContentType("application/octet-stream;charset=UTF-8");
        return response.getOutputStream();
    }

    /**
     * 将输入流写入到输出流
     */
    private static void streamWriter(InputStream inStream, OutputStream outStream, Integer unitLength) throws IOException {
        inStream = new BufferedInputStream(inStream);
        outStream = new BufferedOutputStream(outStream);
        if (unitLength == null || unitLength <= 0) {
            unitLength = 1;
        }
        byte[] data = new byte[unitLength * 1024];
        int size;
        while ((size = inStream.read(data)) != -1) {
            outStream.write(data, 0, size);
        }
        outStream.flush();
    }

    /**
     * 关闭 输入流/输出流
     */
    private static void closeStreamObject(OutputStream outStream, InputStream inStream, HttpURLConnection urlConnection) {
        try {
            if (outStream != null) {
                outStream.close();
            }
            if (inStream != null) {
                inStream.close();
            }
            if (urlConnection != null) {
                urlConnection.disconnect();
            }
        } catch (IOException e) {
            log.error("object close failure: " + e);
        }
    }

    /**
     * 获取日期文件夹路径
     */
    public static String getFolderPath(LocalDateTime localDateTime) {
        String day = localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        String month = localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM"));
        String year = localDateTime.format(DateTimeFormatter.ofPattern("yyyy"));
        return MessageFormat.format("/{0}/{1}/{2}/", year, month, day);
    }

    /**
     * 获取日期文件夹路径
     */
    public static String getFolderPath(Date date) {
        Calendar instance = Calendar.getInstance();
        instance.setTime(date);
        String year = String.format("%04d", instance.get(Calendar.YEAR));
        String month = year + "-" + String.format("%02d", instance.get(Calendar.MONTH) + 1);
        String day = month + "-" + String.format("%02d", instance.get(Calendar.DAY_OF_MONTH));
        return MessageFormat.format("/{0}/{1}/{2}", year, month, day);
    }

//CHECKSTYLE:ON
}
